Skip to content

Post-merge-review: use scope manager for block-param tracking in template-no-obsolete-elements#2676

Draft
johanrd wants to merge 7 commits intoember-cli:masterfrom
johanrd:night_fix/template-no-obsolete-elements
Draft

Post-merge-review: use scope manager for block-param tracking in template-no-obsolete-elements#2676
johanrd wants to merge 7 commits intoember-cli:masterfrom
johanrd:night_fix/template-no-obsolete-elements

Conversation

@johanrd
Copy link
Copy Markdown
Contributor

@johanrd johanrd commented Apr 13, 2026

Summary

Replaces the manual block-param stack with sourceCode.getScope(node.parent) + a walk up the scope chain. Uses the parent scope rather than the element's own scope so an element's own as |x| params don't shadow its own tag — e.g. <marquee as |marquee|> must still flag the outer <marquee>.

Blocked by upstream

ember-tooling/ember-eslint-parser#189. The HBS parser currently builds an empty scope manager, so Glimmer block params aren't registered for .hbs files. The failing test {{#let ... as |plaintext|}}<plaintext /> in HBS mode documents this gap and will start passing once that PR is merged and consumed here.

GTS templates work today because the gjs/gts parser already registers block params.

Test plan

  • GTS: <plaintext> / <marquee> flagged
  • GTS: {{#let ... as |plaintext|}}<plaintext /> not flagged (scope sees the block param)
  • GTS: <Comp as |plaintext|><plaintext /> not flagged (element-level block params)
  • GTS: <marquee as |marquee|> still flagged (parent scope trick)
  • HBS: {{#let ... as |plaintext|}}<plaintext /> not flagged — blocked on upstream PR 189
  • HBS: <marquee>, <acronym>, etc. flagged

The rule suppressed obsolete-element reports when the tag name shadows a
block param from a GlimmerBlockStatement (e.g. {{#let (...) as |marquee|}}).
It did not track element-level block params (<Comp as |marquee|>), so
inside an angle-bracket component the shadowing was ignored and the tag
was falsely reported. Push element block params on enter and pop on exit,
mirroring the existing GlimmerBlockStatement handling.
@johanrd johanrd force-pushed the night_fix/template-no-obsolete-elements branch from 511b615 to 029c2c0 Compare April 13, 2026 10:01
@johanrd johanrd marked this pull request as ready for review April 13, 2026 10:34
// Element-level block params (e.g. `<Comp as |param|>`) are scoped to
// the children, so push them after the obsolete check. Pop on exit.
const elementParams = node.blockParams || [];
blockParamsInScope.push(...elementParams);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be the responsibility of the scope manager?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a clarification above blockParamsInScope now.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kinda seems like we should fix that rather than add a work-around here, ya?

Copy link
Copy Markdown
Contributor Author

@johanrd johanrd Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, maybe, although I'm not sure how to approach that.

To my understanding, getScope() runs into two problems:

HBS mode: ember-eslint-parser's HBS path creates an intentionally empty scope manager — Glimmer block params from {{#let ... as |x|}} and <Comp as |x|> are not registered, so getScope() sees nothing.

GTS mode: at the GlimmerElementNode visitor, the element's own as |x| params are already visible in scope. So getScope() at <marquee as |marquee|> test would find marquee in scope and incorrectly suppress the flag. The push-after-check ordering handles this: the element is checked against outer params only, then its own are pushed for its children.

or were you thinking something else completely? upstream to ember-eslint-parser? thanks.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switched to scope-manager (getScope(node.parent) + chain walk) as suggested. 36/37 tests pass; the one failing HBS test is blocked on ember-tooling/ember-eslint-parser#189

johanrd added 3 commits April 13, 2026 20:50
…params

Replaces the manual block-param stack with sourceCode.getScope(node.parent)
+ a walk up the scope chain. GTS templates work today (36/37 tests pass).

BLOCKED BY UPSTREAM: ember-tooling/ember-eslint-parser#189. The HBS parser
currently builds an empty scope manager, so Glimmer block params aren't
registered for .hbs files. The failing test
`{{#let ... as |plaintext|}}<plaintext />` documents this gap and will
start passing once PR 189 is merged and consumed here.

Uses getScope(node.parent) rather than getScope(node) so an element's
own `as |x|` params (attached to that element's block scope) don't
shadow its own tag — e.g. `<marquee as |marquee|>` must still flag the
outer <marquee>.
@johanrd johanrd force-pushed the night_fix/template-no-obsolete-elements branch from 3a7cb52 to 6189818 Compare April 15, 2026 19:52
@johanrd johanrd changed the title Post-merge-review: Fix template-no-obsolete-elements: track element-level block params Post-merge-review: use scope manager for block-param tracking in template-no-obsolete-elements Apr 15, 2026
@johanrd johanrd requested a review from NullVoxPopuli April 15, 2026 19:54
@johanrd johanrd marked this pull request as draft April 15, 2026 20:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants